﻿using System;
using System.Collections.Generic;

using System.Data.Entity;
using System.Data.Entity.Core.Objects.DataClasses;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CrawlerFramework.Repository
{
    public class BaseGenericRepository<C, T> : GenericRepository.EF.Repository<C, T>
        where C : System.Data.Entity.DbContext, new()
        where T : class
    {
        public BaseGenericRepository(bool lazyLoad = false)
        {
            Context.Configuration.LazyLoadingEnabled = lazyLoad;
        }

        public virtual void Attach(T entity)
        {
            Context.Entry(entity).State = EntityState.Detached;
            Context.Set<T>().Attach(entity);
        }

        public virtual T Detach(T entity)
        {
            Context.Entry(entity).State = EntityState.Detached;
            return entity;
        }

        public virtual void InsertOrUpdate(T entity, int id)
        {
            if (id == 0)
            {
                this.Add(entity);
            }
            else
            {
                this.Edit(entity);
            }
        }

        public override IQueryable<T> All
        {
            get
            {
                var where = new Func<T, bool>(arg =>
                {
                    var isDelete = arg.GetType().GetProperty("IsDelete");
                    return isDelete == null || !(bool)isDelete.GetValue(arg);
                });

                return base.All.Where(where).AsQueryable<T>();
            }
        }

        public override void Add(T entity)
        {
            var insertedDate = entity.GetType().GetProperty("InsertedDate");
            if (insertedDate != null)
                insertedDate.SetValue(entity, DateTime.Now);
            base.Add(entity);
        }

        public override void Delete(T entity)
        {
            var isDelete = entity.GetType().GetProperty("IsDelete");
            if (isDelete != null)
            {
                isDelete.SetValue(entity, true);
                this.Edit(entity);
            }
            else
                base.Delete(entity);
        }

        public override void Edit(T entity)
        {
            var updatedDate = entity.GetType().GetProperty("UpdatedDate");
            if (updatedDate != null)
                updatedDate.SetValue(entity, DateTime.Now);

            this.Context.Entry(entity).State = EntityState.Modified;
        }

        public override IQueryable<T> FindBy(Expression<Func<T, bool>> predicate)
        {
            var where = new Func<T, bool>(arg =>
            {
                var isDelete = arg.GetType().GetProperty("IsDelete");
                return isDelete == null || !(bool)isDelete.GetValue(arg);
            });

            var collection = base.FindBy(predicate).Where(where).AsQueryable();
            return collection;
        }

        public virtual T Single(Expression<Func<T, bool>> predicate)
        {
            return FindBy(predicate).FirstOrDefault();
        }
    }
}
